#include <QtGui>

#include "mainwindow.h"
#include "linearfilter.h"
#include "medianfilter.h"

MainWindow::MainWindow()
{
    imageLabel = new QLabel;
    imageLabel->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
    setCentralWidget(imageLabel);

    undoPointer = undoStack.end();

    createActions();
    createMenus();
    createToolBars();
    createStatusBar();

    readSettings();

    loadFile(":/images/lena.gif");
}

void MainWindow::open()
{
    QString fileName = QFileDialog::getOpenFileName(this);
    if (!fileName.isEmpty())
        loadFile(fileName);
}

bool MainWindow::save()
{
    if (curFile.isEmpty()) {
        return saveAs();
    } else {
        return saveFile(curFile);
    }
}

bool MainWindow::saveAs()
{
    QString fileName = QFileDialog::getSaveFileName(this);
    if (fileName.isEmpty())
        return false;

    return saveFile(fileName);
}

void MainWindow::undo()
{
    if (undoPointer == undoStack.begin()) return;
    //--undoPointer;
    imageLabel->setPixmap(*--undoPointer);
    undoAct->setEnabled(undoPointer != undoStack.begin());
    redoAct->setEnabled(undoPointer != undoStack.end() - 1);
}

void MainWindow::redo()
{
    if (undoPointer == undoStack.end()) return;
    //++undoPointer;
    imageLabel->setPixmap(*++undoPointer);
    undoAct->setEnabled(undoPointer != undoStack.begin());
    redoAct->setEnabled(undoPointer != undoStack.end() - 1);
}

void MainWindow::about()
{
   QMessageBox::about(this, tr("About Image-Filters"),
            tr("The <b>image-filters</b> written by Tomas Balsys"));
}

void MainWindow::meanFilter()
{
    LinearFilter f(sizeSpinBox->value());
    filter(&f);
}

void MainWindow::medianFilter()
{
    MedianFilter f(sizeSpinBox->value());
    filter(&f);
}

void MainWindow::filter(Filter *filter)
{
    QImage image = imageLabel->pixmap()->toImage();

    connect(stopButton, SIGNAL(clicked()), filter, SLOT(cancel()));
    connect(filter, SIGNAL(progress(int)), progress, SLOT(setValue(int)));
    imageLabel->setPixmap(QPixmap::fromImage(filter->filtered(image)));
    disconnect(filter, SIGNAL(progress(int)), progress, SLOT(setValue(int)));
    disconnect(stopButton, SIGNAL(clicked()), filter, SLOT(cancel()));

    progress->reset();

    undoStack.erase(undoPointer+1, undoStack.end());
    undoStack.push(*imageLabel->pixmap());
    undoPointer = undoStack.end() - 1;
    undoAct->setEnabled(undoPointer != undoStack.begin());
    redoAct->setEnabled(undoPointer != undoStack.end() - 1);
}

void MainWindow::createActions()
{
    openAct = new QAction(QIcon(":/images/open.png"), tr("&Open..."), this);
    openAct->setShortcut(tr("Ctrl+O"));
    openAct->setStatusTip(tr("Open an existing file"));
    connect(openAct, SIGNAL(triggered()), this, SLOT(open()));

    saveAct = new QAction(tr("&Save"), this);
    saveAct->setStatusTip(tr("Save the document to disk"));
    connect(saveAct, SIGNAL(triggered()), this, SLOT(save()));

    saveAsAct = new QAction(QIcon(":/images/save.png"), tr("Save &As..."), this);
    saveAsAct->setShortcut(tr("Ctrl+S"));
    saveAsAct->setStatusTip(tr("Save the document under a new name"));
    connect(saveAsAct, SIGNAL(triggered()), this, SLOT(saveAs()));

    undoAct = new QAction(QIcon(":/images/undo.png"), tr("&Undo"), this);
    undoAct->setShortcut(tr("Ctrl+Z"));
    undoAct->setStatusTip(tr("Undo the last operation"));
    undoAct->setEnabled(false);
    connect(undoAct, SIGNAL(triggered()), this, SLOT(undo()));

    redoAct = new QAction(QIcon(":/images/redo.png"), tr("&Redo"), this);
    redoAct->setShortcut(tr("Ctrl+Y"));
    redoAct->setStatusTip(tr("Redo the last operation"));
    redoAct->setEnabled(false);
    connect(redoAct, SIGNAL(triggered()), this, SLOT(redo()));

    exitAct = new QAction(tr("E&xit"), this);
    exitAct->setShortcut(tr("Ctrl+Q"));
    exitAct->setStatusTip(tr("Exit the application"));
    connect(exitAct, SIGNAL(triggered()), this, SLOT(close()));

    meanAct = new QAction(tr("Mean"), this);
    meanAct->setStatusTip(tr("Mean filter (linear)"));
    connect(meanAct, SIGNAL(triggered()), this, SLOT(meanFilter()));

    medianAct = new QAction(tr("Median"), this);
    medianAct->setStatusTip(tr("Median filter (non-linear)"));
    connect(medianAct, SIGNAL(triggered()), this, SLOT(medianFilter()));

    aboutAct = new QAction(tr("&About"), this);
    aboutAct->setStatusTip(tr("Show the application's About box"));
    connect(aboutAct, SIGNAL(triggered()), this, SLOT(about()));

    aboutQtAct = new QAction(tr("About &Qt"), this);
    aboutQtAct->setStatusTip(tr("Show the Qt library's About box"));
    connect(aboutQtAct, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
}

void MainWindow::createMenus()
{
    fileMenu = menuBar()->addMenu(tr("&File"));
    fileMenu->addAction(openAct);
    fileMenu->addAction(saveAct);
    fileMenu->addAction(saveAsAct);
    fileMenu->addSeparator();
    fileMenu->addAction(exitAct);

    editMenu = menuBar()->addMenu(tr("&Edit"));
    editMenu->addAction(undoAct);
    editMenu->addAction(redoAct);

    filtersMenu = menuBar()->addMenu(tr("Filte&rs"));
    filtersMenu->addAction(meanAct);
    filtersMenu->addAction(medianAct);

    menuBar()->addSeparator();

    helpMenu = menuBar()->addMenu(tr("&Help"));
    helpMenu->addAction(aboutAct);
    helpMenu->addAction(aboutQtAct);
}

void MainWindow::createToolBars()
{
    fileToolBar = addToolBar(tr("File"));
    fileToolBar->addAction(openAct);
    fileToolBar->addAction(saveAsAct);

    editToolBar = addToolBar(tr("Edit"));
    editToolBar->addAction(undoAct);
    editToolBar->addAction(redoAct);

    sizeSpinBox = new QSpinBox;
    sizeSpinBox->setRange(1, 31);
    sizeSpinBox->setSingleStep(2);
    sizeSpinBox->setValue(3);
    sizeSpinBox->setKeyboardTracking(false);
    sizeSpinBox->setAccelerated (false);

    sizeLabel = new QLabel(tr("Filter &Size:"));
    sizeLabel->setBuddy(sizeSpinBox);

    filtersButton = new QPushButton(tr("&Apply filter"));
    filtersButton->setMenu(filtersMenu);

    stopButton = new QPushButton(tr("S&top"));
    
    filtersToolBar = addToolBar(tr("Filters"));
    filtersToolBar->addWidget(sizeLabel);
    filtersToolBar->addWidget(sizeSpinBox);
    filtersToolBar->addWidget(filtersButton);
    filtersToolBar->addWidget(stopButton);
}

void MainWindow::createStatusBar()
{
    progress = new QProgressBar(this);
    progress->setMinimum(0);

    statusBar()->addPermanentWidget(progress);
    statusBar()->showMessage(tr("Ready"));
}

void MainWindow::readSettings()
{
    QSettings settings("Trolltech", "image-filters");
    QPoint pos = settings.value("pos", QPoint(200, 200)).toPoint();
    QSize size = settings.value("size", QSize(400, 400)).toSize();
    resize(size);
    move(pos);
}

void MainWindow::writeSettings()
{
    QSettings settings("Trolltech", "image-filters");
    settings.setValue("pos", pos());
    settings.setValue("size", size());
}

void MainWindow::loadFile(const QString &fileName)
{
    QApplication::setOverrideCursor(Qt::WaitCursor);
    QPixmap pixmap;
    bool ok = pixmap.load(fileName);
    imageLabel->setPixmap(pixmap);
    undoStack.push(pixmap);
    undoPointer = undoStack.begin();
    progress->setMaximum(pixmap.height()-1);
    QApplication::restoreOverrideCursor();
    if (!ok) {
        QMessageBox::information(this, tr("image-filters"),
                                 tr("Cannot read file %1.")
                                 .arg(fileName));
        return;
    }

    imageLabel->setPixmap(pixmap);


    setCurrentFile(fileName);
    statusBar()->showMessage(tr("File loaded"), 2000);
}

bool MainWindow::saveFile(const QString &fileName)
{
    QApplication::setOverrideCursor(Qt::WaitCursor);
    bool ok = imageLabel->pixmap()->save(fileName);
    QApplication::restoreOverrideCursor();
    if (!ok) {
        QMessageBox::warning(this, tr("image-filters"),
                             tr("Cannot write file %1.")
                             .arg(fileName));
        return false;
    }

    setCurrentFile(fileName);
    statusBar()->showMessage(tr("File saved"), 2000);
    return true;
}

void MainWindow::setCurrentFile(const QString &fileName)
{
    curFile = fileName;
    setWindowModified(false);
    setWindowTitle(curFile.isEmpty()
                   ? tr("image-filters")
                   : tr("%1[*] - %2").arg(QFileInfo(curFile).fileName()).arg(tr("image-filters")));
}
